package com.qdlc.p2p.biz.service.user.impl;

import java.text.MessageFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import com.qdlc.p2p.biz.executer.impl.NewActivityAwardExecutor;
import com.qdlc.p2p.biz.processor.TaskProcessorHelper;
import com.qdlc.p2p.biz.processor.event.NoticeTemplateValueEvent;
import com.qdlc.p2p.biz.processor.task.NoticeTemplateSmsTaskProcessor;
import com.qdlc.p2p.biz.service.AdditionalUserCardService;
import com.qdlc.p2p.biz.service.UserCacheService;
import com.qdlc.p2p.biz.service.UserLoginRecordService;
import com.qdlc.p2p.biz.service.UserService;
import com.qdlc.p2p.biz.service.user.UserMobilePhoneService;
import com.qdlc.p2p.biz.service.user.UserRegistService;
import com.qdlc.p2p.biz.util.UserLoginUtil;
import com.qdlc.p2p.biz.util.UserReturnResult;
import com.qdlc.p2p.common.constant.Global;
import com.qdlc.p2p.common.constant.NoticeTplNid;
import com.qdlc.p2p.common.constant.UserImportType;
import com.qdlc.p2p.common.constant.UserNature;
import com.qdlc.p2p.common.constant.UserType;
import com.qdlc.p2p.common.core.ReturnResult;
import com.qdlc.p2p.common.core.queue.ITaskProcessor;
import com.qdlc.p2p.common.core.queue.TaskProcessorException;
import com.qdlc.p2p.common.core.redis.JedisCache;
import com.qdlc.p2p.common.core.redis.JedisCacheFactory;
import com.qdlc.p2p.common.core.redis.JedisCallable;
import com.qdlc.p2p.common.enums.EnumActicityPlanNid;
import com.qdlc.p2p.common.enums.EnumCardType;
import com.qdlc.p2p.common.util.DateUtil;
import com.qdlc.p2p.common.util.LogFactory;
import com.qdlc.p2p.common.util.MessageUtil;
import com.qdlc.p2p.common.util.RandomUtil;
import com.qdlc.p2p.common.util.StringUtil;
import com.qdlc.p2p.common.util.ValidateUtil;
import com.qdlc.p2p.common.util.code.MD5;
import com.qdlc.p2p.dal.checkrule.LoginRuleCheck;
import com.qdlc.p2p.dal.common.NoticeTypeHelper.NidType;
import com.qdlc.p2p.dal.common.RuleCheckHelper;
import com.qdlc.p2p.dal.common.SystemConfigHelper;
import com.qdlc.p2p.dal.common.SystemConfigHelper.Nid;
import com.qdlc.p2p.dal.dao.AccountDao;
import com.qdlc.p2p.dal.dao.MemberInfosDao;
import com.qdlc.p2p.dal.dao.ScoreDao;
import com.qdlc.p2p.dal.dao.TppMemberAgentDao;
import com.qdlc.p2p.dal.dao.UserCacheDao;
import com.qdlc.p2p.dal.dao.UserCreditDao;
import com.qdlc.p2p.dal.dao.UserDao;
import com.qdlc.p2p.dal.dao.UserIdentifyDao;
import com.qdlc.p2p.dal.dao.UserInviteDao;
import com.qdlc.p2p.dal.dao.UserLoginExtDao;
import com.qdlc.p2p.dal.dto.Account;
import com.qdlc.p2p.dal.dto.MemberAgent;
import com.qdlc.p2p.dal.dto.MemberInfos;
import com.qdlc.p2p.dal.dto.Score;
import com.qdlc.p2p.dal.dto.User;
import com.qdlc.p2p.dal.dto.UserCache;
import com.qdlc.p2p.dal.dto.UserCredit;
import com.qdlc.p2p.dal.dto.UserIdentify;
import com.qdlc.p2p.dal.dto.UserInvite;
import com.qdlc.p2p.dal.dto.UserLoginExt;
import com.qdlc.p2p.dal.dto.UserLoginRecord;
import com.qdlc.p2p.dal.model.UserModel;
import com.qdlc.p2p.dal.util.SystemConfigs;
import com.qdlc.p2p.dal.util.UserTypeUtils;
import com.qdlc.p2p.dal.util.UserUtils;

@Service
public class UserRegistServiceImpl implements UserRegistService{

	private static final Logger exceptionLog = LogFactory.EXCEPTION_LOGGER;
	
	private static final String USER_REGIST_PHONE_KEY_PREFIX = "user_regist_phone_key_";
	
	private static final String USER_REGIST_USERNAME_KEY_PREFIX = "user_regist_username_key_";
	
	@Resource
	private UserDao userDao;
	
	@Resource
	private UserService userService;
	
	@Resource
	UserCacheService userCacheService;
	
	@Resource
	UserLoginRecordService userLoginRecordService;
	
	@Resource
	UserCacheDao userCacheDao;
	
	@Resource
	UserIdentifyDao userIdentifyDao;
	
	@Resource
	AccountDao accountDao;
	
	@Resource
	UserCreditDao userCreditDao;
	
	@Resource
	ScoreDao scoreDao;
	
	@Resource
	UserLoginExtDao userLoginExtDao;
	
	@Resource
	MemberInfosDao memberInfosDao;
	
	@Resource
	TppMemberAgentDao tppMemberAgentDao;
	
	@Resource
	UserInviteDao userInviteDao;
	
	@Resource
	UserMobilePhoneService userMobilePhoneService;
	
	@Resource
	AdditionalUserCardService additionalUserCardService;
	
	/**
	 * 检测注册基本信息
	 * @param userModel
	 * @author linya
	 * @return
	 */
	@Override
	public ReturnResult checkRegisterBaseInfo(UserModel userModel){
		
		//1. 检测验证码
		String vCode = StringUtils.trimToEmpty(userModel.getValidCode());
		if (vCode.isEmpty()) {
			return new ReturnResult(MessageUtil.getMessage("E30005"));
		}
		if (!ValidateUtil.checkValidCode(vCode)) {
			return new ReturnResult(MessageUtil.getMessage("E30006"));
		}
		
		//2. 检测用户名格式(字符检测)
		if (!ValidateUtil.isUserName(userModel.getUserName())) {
			return new ReturnResult("用户名格式错误!");
		}
		
		//3. 检测密码(空检测、字符检测、一致性检测)
		String pwd = userModel.getPwd();
		String confirmNewPwd = userModel.getConfirmNewPwd();
		if (StringUtil.isBlank(pwd)) {
			return new ReturnResult("密码不能为空!");
		}
		if (StringUtil.isBlank(confirmNewPwd)) {
			return new ReturnResult("确认密码不能为空!");
		}
		String checkPwd = ValidateUtil.isPwd(pwd);
		if (StringUtil.isNotBlank(checkPwd)) {
			return new ReturnResult(checkPwd);
		}
		if (!pwd.equals(confirmNewPwd)) {
			return new ReturnResult("两次输入的密码不一致！");
		}
        
		return ReturnResult.SUCCESS;
	}
	
	
	/**
	 * 检测注册手机号码
	 * @param mobilePhone
	 * @author linya
	 * @return
	 */
	private ReturnResult checkMobilePhone(String mobilePhone){
		
        //1. 检测手机号码为空
        if (StringUtil.isBlank(mobilePhone)) {
        	return new ReturnResult("手机号码不能为空！");
        }
        
        //2. 检测手机号码是否已经注册
        int count = userService.countByMobilePhone(mobilePhone);
        if (count > 0) {
        	return new ReturnResult("手机号码已存在！");
        }
        
		return ReturnResult.SUCCESS;
	}
	
	/**
	 * 发送注册验证码
	 * @author linya
	 * @return
	 */
	@Override
	public ReturnResult doSendValidCode(UserModel userModel, String mobilePhone){
		
		//1. 检测注册手机号码
		ReturnResult checkResult = checkMobilePhone(mobilePhone);
		if(checkResult.isError()){
			return checkResult;
		}
		
		//2. 发送注册验证码
		ReturnResult sendSmsResult = null;
		try {
	        String code = RandomUtil.code();
	        System.out.println("++++ 注册验证码:" + code);
	        NoticeTemplateValueEvent noticeEvent = NoticeTemplateValueEvent.newInstance(userModel, NoticeTplNid.NOTICE_REG, NidType.NOTICE_SMS)
	        			.addSendData("code", code)
	        			.addSendData("phone", mobilePhone)
	        			.addSendData("mobilePhone", mobilePhone)
	        			.addSendData("vtime", SystemConfigHelper.getValue(Nid.VERIFY_CODE_TIME))
	        			.addSendData("webname", SystemConfigs.WEB_NAME);
	        ITaskProcessor taskProcessor = TaskProcessorHelper.getProcessor(NoticeTemplateSmsTaskProcessor.class);
			taskProcessor.process(noticeEvent);
			
			//如果短信发送成功，缓存验证码到Redis中，有效时长30分钟
			JedisCacheFactory.newInstance(Boolean.class).set(NoticeTplNid.NOTICE_REG + mobilePhone + code, true, 30, TimeUnit.MINUTES);
		
		} catch (TaskProcessorException e) {
			exceptionLog.error(MessageFormat.format("{0}注册,发送短信失败!", userModel), e);
			sendSmsResult = new ReturnResult("发送短信失败!");
		}
        
		//3. 设置SUCCESS，发送短信成功
		if(sendSmsResult == null){
			sendSmsResult = ReturnResult.SUCCESS;
		}
		
		return sendSmsResult;
	}

	
	/**
	 * 检测注册提交（使用缓存数据）
	 * @param userModel
	 * @return
	 */
	private ReturnResult checkSubmitRegist(UserModel userModel){
		
		JedisCache<Integer> jedisCache = JedisCacheFactory.newInstance(Integer.class);
		
		//1. 检测用户名是否已经存在
		final String userName = userModel.getUserName();
		int usernameCount = jedisCache.get(USER_REGIST_USERNAME_KEY_PREFIX + userName, new JedisCallable<Integer>() {
											public Integer call() {
												return userDao.countByUserName(userName);
											}
										});
		if(usernameCount > 0){
			return new ReturnResult("用户名已经存在!");
		}
		
		//2. 检测手机号码是否已经存在
		final String mobilePhone = userModel.getMobilePhone();
		int mobilePhoneCont = jedisCache.get(USER_REGIST_PHONE_KEY_PREFIX + mobilePhone, new JedisCallable<Integer>() {
											public Integer call() {
												return userDao.countByMobilePhone(mobilePhone);
											}
										});
		if(mobilePhoneCont > 0){
			return new ReturnResult("手机号码已经存在!");
		}
		
		return ReturnResult.SUCCESS;
	}
	
	/**
	 * 创建注册新用户
	 * @param userModel
	 * @return
	 */
	private User populateRegistUser(UserModel userModel, boolean isPartner){
		User user = new User();
		user.setUserName(userModel.getUserName());
		user.setMobilePhone(userModel.getMobilePhone());
		user.setPwd(MD5.encode(userModel.getPwd()));
		Date addTime = userModel.getAddTime();
		if(addTime == null){
			addTime = DateUtil.getNow();
		}
		user.setAddTime(addTime);
		return user;
	}
	
	/**
	 * 注册操作
	 * @param userModel
	 * @param isPartner 是否是联合用户
	 * @return
	 * @throws Exception 
	 */
	@Override
	public ReturnResult doRegister(UserModel userModel, boolean isPartner) throws Exception{
		
		// 判断验证码是否有效（从缓存数据中获取）
		if(!isPartner){
			String code = userModel.getCode();
			String mobilePhone = userModel.getMobilePhone();
			String registCodekey = NoticeTplNid.NOTICE_REG + mobilePhone + code;
			JedisCache<Boolean> jedisCache = JedisCacheFactory.newInstance(Boolean.class);
			Boolean hasValidCode = jedisCache.get(registCodekey);
			if(hasValidCode == null || !hasValidCode){
				return new ReturnResult("验证码不正确或已过期!");
			}
			jedisCache.delete(registCodekey);
		}

		// 注册前检测，检测用户名和手机号码是否已经存在
		ReturnResult checkResult = checkSubmitRegist(userModel);
		if(checkResult.isError()){
			return checkResult;
		}
		
		// 处理注册流程,创建注册用户对象
		User user = populateRegistUser(userModel, isPartner);
		
		// 保存User到数据库
		userDao.save(user);
		
		// 保存用户登录扩展信息
		saveUserLoginExt(user);
		
		// 保存用户性质信息
		saveUserCache(userModel, user, isPartner);
		
		// 用户认证信息
        userIdentifyDao.save(new UserIdentify(user.getUserId()));
        
		// 资金账户
        accountDao.save(new Account(user.getUserId()));
        
        // 用户信用度
        userCreditDao.save(new UserCredit(user));
        
		// 积分信息 
        scoreDao.save(new Score(user));
		
        //注册后置操作
        postRegistHandle(userModel, user);
        
		return new UserReturnResult(user);
	}
	
	/**
	 * 保存UserLoginExt，用于使用手机号、用户名、邮箱等都可以登录
	 * @param user
	 */
	private void saveUserLoginExt(User user){
		//5. 登录扩展表(插入用户名和手机号码，用于登录使用)
        UserLoginExt userLoginExt = new UserLoginExt(user);
        userLoginExt.setUserName(user.getUserName());
        userLoginExt.setAddTime(user.getAddTime());
        userLoginExtDao.save(userLoginExt);
        userLoginExt = new UserLoginExt(user);
        userLoginExt.setUserName(user.getMobilePhone());
        userLoginExt.setAddTime(user.getAddTime());
        userLoginExtDao.save(userLoginExt);
	}
	
	/**
	 * 保存用户附属信息 UserCache
	 * @param userModel
	 * @param user
	 * @param isPartner
	 */
	private void saveUserCache(UserModel userModel, User user, boolean isPartner){
        UserCache userCache = new UserCache(user, Global.getIP());
        // 1投资人，2借款人，3 借款公司
        if (userModel.getUserType() == UserType.INVESTMENT_BORROWER) {
        	userCache.setUserType(UserType.INVESTMENT_BORROWER);
			userCache.setUserNature(userModel.getUserNature());
        }else {
        	userCache.setUserNature(UserNature.NATURAL);
        	userCache.setUserType(UserType.INVESTOR);
	    }
        
        // 用户导入类型
        if (isPartner) {
        	userCache.setIsImp(UserImportType.IMPORT);
        }else{
        	userCache.setIsImp(UserImportType.USER_REGIST);
        }
        
        // 默认头像
        userCache.setAvatarPicPath("/avatar/01-png");  
        
        userCacheDao.save(userCache);
        
        //如果用户是借款人，需要设置企业信息表和经办人表
        long userId = user.getUserId();
        if(UserTypeUtils.isBorrowOrInverstment(userId)){
        	//企业信息表
        	MemberInfos mi = new MemberInfos();
        	mi.setUserId(user.getUserId());
        	memberInfosDao.save(mi);
        	//经办人信息表
        	MemberAgent ma = new MemberAgent();
        	ma.setUser(user);
        	tppMemberAgentDao.save(ma);
        }
	}
	
	/**
	 * 注册数据保存后，后置处理操作
	 * @param userModel
	 * @param user
	 * @throws Exception
	 */
	private void postRegistHandle(UserModel userModel, User user) throws Exception{
		
		//1. 注册手机自动认证
		userMobilePhoneService.modifyRegistMobilePhone(user, user.getMobilePhone());
        
        //2. 邀请好友赠送给邀请者
        User inviteUser = userModel.getInviteUser();
		if (inviteUser != null) {
			UserInvite iu = new UserInvite();
			iu.setInviteTime(DateUtil.getNow());
			iu.setUserId(user.getUserId());
			iu.setInviteUser(inviteUser.getUserId());
			userInviteDao.insert(iu);
		}
        if (inviteUser != null){
        	NewActivityAwardExecutor.giveByTache(userModel.getInviteUser(), EnumActicityPlanNid.INVITE.getValue());
        }
        // 注册发放活动奖励
        NewActivityAwardExecutor.giveByTache(user, EnumActicityPlanNid.REGISTER.getValue());
        
        //3. 处理登录规则
        LoginRuleCheck loginRuleCheck = RuleCheckHelper.getValue(LoginRuleCheck.class);
        if(loginRuleCheck.is_auto_login){
        	//缓存注册用户ID
        	UserLoginUtil.cacheLoginUser(user.getUserId());
        	// 更新用户附属信息
        	UserCache userCache = UserUtils.getUserCacheByUserId(user.getUserId());
        	userCache.setLoginTime(DateUtil.getNow());
        	userCache.setLoginFailTimes(0);
        	userCacheService.update(userCache);
        	
        	// 更新用户登录信息
        	UserLoginRecord record = new UserLoginRecord();
        	record.setLoginIp(Global.getIP());
        	record.setLoginTime(DateUtil.getNow());
        	record.setUser(user);
        	userLoginRecordService.record(record);
        }
	}
}
